package utils

import (
	"sync"
	"sync/atomic"
)

/***
  dlink 是一个基础类, 一般不直接对外服务
     基于dlink进行封装的有 SyncQueue

  dlinklist 加入游标
     初始化, 游标在头部
     SeekFirst 游标移动到头部, 如果没有值返回nil
     SeekLast  游标移动到尾部, 如果没有值返回nil
     FetchNext 游标移动到下一个, 如果已经到底尾部,返回nil

     如果移除元素是当前元素,则游标移动到之前元素的下一个
*/

type DLinkNode struct {
	tag      byte
	owner    *DLinklist
	pre      *DLinkNode
	next     *DLinkNode
	Value    interface{}
	poolflag int32 // 如果是Pool则1为使用, 2未使用
}

var (
	link_node_pool *sync.Pool = &sync.Pool{New: func() interface{} {
		return &DLinkNode{
			pre:      nil,
			next:     nil,
			Value:    nil,
			poolflag: 2,
		}
	}}
)

type DLinklist struct {
	head      *DLinkNode
	tail      *DLinkNode
	fixedHead *DLinkNode
	fixedTail *DLinkNode
	cursor    *DLinkNode
	cnt       int32
}

func NewDlinknodeFromPool() *DLinkNode {
	rval := link_node_pool.Get().(*DLinkNode)
	rval.poolflag = 1 // 正在使用
	return rval
}

func NewDlinknode() *DLinkNode {
	return &DLinkNode{
		pre:   nil,
		next:  nil,
		Value: nil,
	}
}

func (this *DLinkNode) Next() *DLinkNode {
	return this.next
}

func (this *DLinkNode) release2Pool() {
	if atomic.CompareAndSwapInt32(&this.poolflag, 1, 2) {
		this.Value = nil
		link_node_pool.Put(this)
	}
}

func NewDlinklist() *DLinklist {
	rval := &DLinklist{
		head:      nil,
		tail:      nil,
		fixedHead: NewDlinknode(),
		fixedTail: NewDlinknode(),
		cnt:       0,
	}
	rval.init()
	return rval
}

func (this *DLinklist) init() {
	this.head = this.fixedHead
	this.tail = this.fixedTail
	this.head.next = this.tail
	this.tail.pre = this.head
	this.fixedHead.Value = "fixHead"
	this.fixedHead.tag = 0xFF
	this.fixedTail.Value = "fixTail"
	this.fixedTail.tag = 0xFE
	this.cursor = this.head
}

/**
 * 插入一个节点到头部,  该节点的pre, next会被改变
 */
func (this *DLinklist) InsertToFirst(node *DLinkNode) {
	this.head.next.pre = node
	node.next = this.head.next
	node.pre = this.head
	this.head.next = node
	node.owner = this
	this.cnt++
}

/**
 * 插入一个节点到尾部, 该节点的pre, next会被改变
 */
func (this *DLinklist) Append(node *DLinkNode) {
	this.tail.pre.next = node
	node.pre = this.tail.pre
	node.next = this.tail
	node.owner = this
	this.tail.pre = node
	this.cnt++
}

func (this *DLinklist) AppendValue(v interface{}) {
	this.Append(&DLinkNode{Value: v})
}

/**
 *  移除一个元素，注意该元素必须是列表中的元素，否则 元素数量会出错
 */
func (this *DLinklist) Remove(node *DLinkNode) bool {
	if this.cnt == 0 {
		return false
	}

	if node.next == nil || node.pre == nil || node.owner != this {
		return false
	}

	if this.cursor == node {
		this.FetchNext()
	}

	node.pre.next = node.next
	node.next.pre = node.pre

	// 再次进行移除时, 可以进行判断
	node.pre = nil
	node.next = nil

	this.cnt--
	return true
}

func (this *DLinklist) SeekFirst() *DLinkNode {
	if this.Count() == 0 {
		this.cursor = this.head
		return nil
	}
	this.cursor = this.head.next
	return this.cursor
}

func (this *DLinklist) SeekLast() *DLinkNode {
	if this.Count() == 0 {
		this.cursor = this.tail
		return nil
	}
	this.cursor = this.tail.pre
	return this.cursor
}

func (this *DLinklist) FetchNext() *DLinkNode {
	if this.cursor == this.tail || this.cursor.next == this.tail {
		this.cursor = this.tail
		return nil
	}
	this.cursor = this.cursor.next
	return this.cursor
}

func (this *DLinklist) FetchPre() *DLinkNode {
	if this.cursor == this.head || this.cursor.pre == this.head {
		this.cursor = this.head
		return nil
	}
	this.cursor = this.cursor.pre
	return this.cursor
}

/**
 * 移除头部一个节点, 返回该节点, 如果为空返回nil
 */
func (this *DLinklist) First() *DLinkNode {
	if this.cnt == 0 {
		return nil
	}

	rval := this.head.next
	return rval
}

func (this *DLinklist) Count() int32 {
	return this.cnt
}

func (this *DLinklist) List() []interface{} {
	if this.cnt == 0 {
		return nil
	}

	lst := make([]interface{}, 0, this.cnt)

	node := this.head.next
	for node != this.tail {
		lst = append(lst, node.Value)
		node = node.next
	}
	return lst
}

func (this *DLinklist) Nodes() []*DLinkNode {
	if this.cnt == 0 {
		return nil
	}

	lst := make([]*DLinkNode, 0, this.cnt)

	node := this.head.next
	for node != this.tail {
		lst = append(lst, node)
		node = node.next
	}
	return lst
}

/**
 * 移除头部一个节点, 返回该节点, 如果为空返回nil
 */
func (this *DLinklist) RemoveFirst() *DLinkNode {
	if this.cnt == 0 {
		return nil
	}

	rval := this.head.next
	this.Remove(rval)
	return rval
}

/**
 * 移除尾部一个节点, 返回该节点, 如果为空返回nil
 */
func (this *DLinklist) RemoveLast() *DLinkNode {
	if this.cnt == 0 {
		return nil
	}

	rval := this.tail.pre
	this.Remove(rval)
	return rval
}

/**
 *  循环
 */
func (this *DLinklist) Range(cb func(val interface{}) bool) int {
	if this.cnt == 0 {
		return 0
	}

	node := this.head.next
	i := 0
	for node != this.tail {
		if cb(node.Value) {
			i++
		}
		node = node.next
	}
	return i
}

/**
 *  循环
 */
func (this *DLinklist) RangeEx(cb func(idx int, val interface{}, removeit *bool) bool, onremove func(node *DLinkNode)) int {
	if this.cnt == 0 {
		return 0
	}

	node := this.head.next
	i := 0

	removeit := false
	for node != this.tail {
		removeit = false
		tmpNode := node
		r := cb(i, tmpNode.Value, &removeit)

		node = node.next
		if removeit {
			this.Remove(tmpNode)
			if onremove != nil {
				onremove(tmpNode)
			}
		}
		if !r {
			break
		}
		i++
	}
	return i
}
